<?php
// +----------------------------------------------------------------------
// | SwiftPHP [ JUST DO ONE THING WELL ]
// +----------------------------------------------------------------------
// | Copyright (c) 2015-2017  http://swiftphp.zhongwenyu.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: zhongwenyu <zhongwenyu1987@163.com> <http://www.zhongwenyu.com>
// +----------------------------------------------------------------------
// | Times: 2017/2/25 20:22
// +----------------------------------------------------------------------
namespace swift\model;
use swift\Db;
use swift\model;

class RelationModel extends Model{

    // 关联定义
    protected $_link = [];

    // 当前操作的关联表
    protected $current = [];

    protected $mainField = false;

    // manySql
    protected $manySql = [];

    /**
     * 设置当前操作的关联表，支持设置关联查询字段
     * @params string|array 关联表名
     * @return object
     */
    public function relation($link = []){
        if(empty($link)){
            if(!empty($this->_link)){
                foreach($this->_link as $k => $v){
                    $this->linkTableName($this->_link[$k] , $k);
                }
                $this->current = $this->_link;
            }
        }elseif(is_string($link)){
            $arr = explode(',' , $link);
            foreach($arr as $v){
                $v = trim($v);
                $this->linkTableName($this->_link[$v] , $v);
                $this->current[$v] = $this->_link[$v];
            }
        }elseif(is_array($link)){
            foreach($link as $k => $v){
                if(!is_numeric($k)){
                    $k = trim($k);
                    $this->linkTableName($this->_link[$k] , $k);
                    $this->_link[$k]['mapping_fields'] = $v;
                    $this->current[$k] = $this->_link[$k];
                }else{
                    $v = trim($v);
                    $this->linkTableName($this->_link[$v] , $v);
                    $this->current[$v] = $this->_link[$v];
                }
            }
        }
        return $this;
    }

    protected function linkTableName(&$link,$key){
        if(!isset($link['table_name'])){
            $table = $key;
        }else{
            $table = $link['table_name'];
        }
        $link['table_name'] = strpos($table , $this->connection['prefix']) === false ? $this->connection['prefix'] . $table : $table;
    }

    /**
     * 关联查询多条数据
     * @params array $where
     * @return array
     */
    public function all($where = []){
        if(!empty($where)){
            $this->where($where);
        }

        // 设置查询字段
        if($this->mainField === false){
            $this->db()->field($this->table . '.*');
        }

        // 软删除筛选
        $this->softdel();

        // 获取查询数据
        $result = $this->db()->select();

        // 输出数据筛选
        $result = $this->dataOutputScreen($result);

        $this->manySql = [];
        $this->mainField = false;

        return $result;
    }

    /**
     * 关联查询一条数据，默认使用innerjoin
     * @params array $where
     * @return array
     */
    public function get($where = []){
        if(!is_null($where)){
            $this->where($where);
        }

        // 设置查询字段
        if($this->mainField === false){
            $this->db()->field($this->table . '.*');
        }

        // 软删除筛选
        $this->softdel();

        // 关联查询
        if(!empty($this->current)){
            foreach($this->current as $v){
                $this->$v['mapping_type']($v);
            }
        }

        // 获取查询数据
        $result = $this->db()->find();

        // 输出数据筛选
        $result = $this->dataOutputScreen($result);

        $this->manySql = [];
        $this->mainField = false;

        return $result;
    }

    // 关联字段加前缀
    protected function prefixField(&$field){
        $field = $this->table . '.' . trim($field);
    }

    /**
     * 数据取出筛选，支持多维数组
     * @access public
     * @param array  $data     数据
     * @return array $data
     */
    protected function dataOutputScreen($data){
        $arr = [];
        if(!empty($data)){
            if(is_numeric(key($data))){
                // 多维数组
                foreach($data as $key => $v){
                    $arr[$key] = $this->dataOutputScreen($v);
                }
            }else{
                // 数据类型转换
                array_walk($data , [$this , 'readTrans'] , $data);
                // 关联查询
                if(!empty($this->manySql)){
                    $pk = $this->db()->getPk();
                    foreach($this->manySql as $k => $v){
                        $k = str_replace($this->connection['prefix'] , '' , $k);
                        $res = $this->query($v , [$pk => $data[$pk]]);
                        if(!empty($res)){
                            $data[$k] = $res;
                        }
                    }
                }
                $arr = $data;
            }
        }
        return $arr;
    }

    /**
     * 软删除筛选
     */
    protected function softdel($table = ''){
        empty($table) && $table = $this->table;
        $allFields = Db::table($table)->getFields();
        if(in_array($this->softfield , $allFields)){
            if(!empty($this->db()->getWhere())){
                $where[] = [$table . '.' . $this->softfield , '=' , 0 , 'and'];
            }else{
                $where[] = [$table . '.' . $this->softfield , '=' , 0];
            }
            $this->db()->where($where);
        }
    }

    /**
     * hasOne查询
     * @params array $link
     */
    protected function hasOne($link){
        // 设置查询字段
        if(isset($link['mapping_fields'])){
            foreach(explode(',',$link['mapping_fields']) as $v){
                $this->db()->field($link['table_name'].'.'.$v);
            }
        }else{
            $this->db()->field($link['table_name'].'.*');
        }

        // 软删除筛选
        $this->softdel($link['table_name']);

        $this->db()->join($link['table_name'],$this->table . '.' . $this->getPk() . '=' . $link['table_name'] . '.' . $link['foreign_key']);
    }

    /**
     * belongsTo查询
     */
    protected function belongsTo($link){
        // 设置查询字段
        if(isset($link['mapping_fields'])){
            foreach(explode(',',$link['mapping_fields']) as $v){
                $this->db()->field($link['table_name'].'.'.$v);
            }
        }else{
            $this->db()->field($link['table_name'].'.*');
        }

        // 软删除筛选
        $this->softdel($link['table_name']);

        if(!isset($link['foreign_key'])){
            $link['foreign_key'] = Db::table($link['table_name'])->getPk();
        }
        $this->db()->join($link['table_name'],$this->table . '.' . $link['parent_key'] . '=' . $link['table_name'] . '.' .$link['foreign_key'] );
    }

    /**
     * hasMany查询
     */
    protected function hasMany($link){
        if(!isset($this->manySql[$link['table_name']])){
            // 设置查询字段
            if(isset($link['mapping_fields'])){
                $field = $link['mapping_fields'];
            }else{
                $field = '*';
            }

            // 软删除筛选
            $allFields = Db::table($link['table_name'])->getFields();
            $where = " where ";
            if(in_array($this->softfield , $allFields)){
                $where .= $link['table_name'] . "." . $this->softfield . '= 0 and ';
            }

            $sql = "select " . $field . " from " . $link['table_name'] . $where . $link['foreign_key'] . "= :" . $this->db()->getPk();

            $this->manySql[$link['table_name']] = $sql;
        }
    }

    /**
     * manyToMany查询
     */
    protected function manyToMany($link){
        if(!isset($this->manySql[$link['table_name']])){
            // 设置查询字段
            if(isset($link['mapping_fields'])){
                foreach(explode(',',$link['mapping_fields']) as $v){
                    $field[] = $link['table_name'].'.'.$v;
                }
                $field = implode(',',$field);
            }else{
                $field = $link['table_name'].'.*';
            }

            // 软删除筛选
            $allFields = Db::table($link['table_name'])->getFields();
            $where = " where ";
            if(in_array($this->softfield , $allFields)){
                $where .= $link['table_name'] . "." . $this->softfield . '= 0 and ';
            }

            strpos($link['relation_table'] , $this->connection['prefix']) === false && $link['relation_table'] = $this->connection['prefix'] . $link['relation_table'];
            $pk = Db::table($link['table_name'])->getPk();
            $sql = "select " . $field . " from " . $link['relation_table'] . " inner join " . $link['table_name'] . " on " . $link['relation_table'] . '.' . $link['relation_foreign_key'] . '=' . $link['table_name'] . '.' . $pk . $where . $link['relation_table'] . '.' . $link['foreign_key'] . '= :'.$this->db()->getPk();

            $this->manySql[$link['table_name']] = $sql;
        }
    }

    /**
     * 设置查询条件
     * @access public
     * @param mixed $field 字段名
     * @param mixed $condition 查询表达式
     * @param mixed $value 字段值
     * @param mixed $type 多个查询条件连接条件
     * @return $this
     */
    public function where($field , $condition = '' , $value = '' , $type = ''){
        if(is_string($field)){
            $this->prefixField($field);
        }elseif(is_array($field)){
            if(is_array(current($field))){
                foreach($field as $k => $v){
                    $this->prefixField($field[$k][0]);
                }
            }else{
                $this->prefixField($field[0]);
            }
        }
        $this->db()->where($field , $condition , $value , $type);
        return $this;
    }

    /**
     * 设置排序
     * @access public
     * @param string  $order   排序
     * @return $this
     */
    public function order($order = ''){
        if(!empty($order)){
            if(strpos($order , ',')){
                $arr = explode(',' , $order);
                foreach($arr as $k => $v){
                    if(strpos($v,$this->table) === false){
                        $this->prefixField($arr[$k]);
                    }
                }
                $order = implode(',' , $arr);
            }else{
                $this->prefixField($order);
            }
            $this->db()->order($order);
        }
        return $this;
    }

    /**
     * 设置查询字段
     * @access public
     * @param array|string  $field   查询字段
     * @param bool          $flag    是否设置不查询字段
     * @return $this
     */
    public function field($field , $flag = false){
        if(!empty($field)){
            if(is_string($field)){
                $field = explode(',',$field);
            }
            foreach($field as $v){
                $this->db()->field($this->table . '.' . $v , $flag);
            }
            $this->mainField = true;
        }
        return $this;
    }
}